home *** CD-ROM | disk | FTP | other *** search
- /* Structured output, compact format */
-
- #include "debugger.h"
- #include "fail.h"
- #include "gc.h"
- #include "intext.h"
- #include "io.h"
- #include "memory.h"
- #include "mlvalues.h"
- #include "reverse.h"
-
- static void output_number(chan, code, val, nbits)
- struct channel * chan;
- int code, nbits;
- long val;
- {
- int i;
- putch(chan, code);
- for (i = nbits - 8; i >= 0; i -= 8) putch(chan, val >> i);
- }
-
- static byteoffset_t obj_counter; /* Number of objects emitted so far */
- static unsigned long size_32; /* Size in words of 32-bit block for struct. */
- static unsigned long size_64; /* Size in words of 64-bit block for struct. */
-
- static void emit_compact(chan, v)
- struct channel * chan;
- value v;
- {
- tailcall:
- if (Is_long(v)) {
- long n = Long_val(v);
- if (n >= 0 && n < 0x40) {
- putch(chan, PREFIX_SMALL_INT + n);
- } else if (n >= -(1 << 7) && n < (1 << 7)) {
- output_number(chan, CODE_INT8, n, 8);
- } else if (n >= -(1 << 15) && n < (1 << 15)) {
- output_number(chan, CODE_INT16, n, 16);
- #ifdef SIXTYFOUR
- } else if (n < -(1L << 31) || n >= (1L << 31)) {
- output_number(chan, CODE_INT64, n, 64);
- #endif
- } else
- output_number(chan, CODE_INT32, n, 32);
- } else {
- header_t hd = Hd_val(v);
- tag_t tag = Tag_hd(hd);
- mlsize_t sz = Wosize_hd(hd);
- asize_t h;
- /* Atoms are treated specially for two reasons: they are not allocated
- in the externed block, and they are automatically shared. */
- if (sz == 0) {
- if (tag < 16) {
- putch(chan, PREFIX_SMALL_BLOCK + tag);
- } else {
- output_number(chan, CODE_BLOCK32, hd, 32);
- }
- } else {
- /* Check if already seen */
- if (2 * obj_counter >= extern_table_size) resize_extern_table();
- h = Hash(v);
- while (extern_table[h].obj != 0) {
- if (extern_table[h].obj == v) {
- byteoffset_t d = obj_counter - extern_table[h].ofs;
- if (d < 0x100) {
- output_number(chan, CODE_SHARED8, d, 8);
- } else if (d < 0x10000) {
- output_number(chan, CODE_SHARED16, d, 16);
- } else {
- output_number(chan, CODE_SHARED32, d, 32);
- }
- return;
- }
- h++;
- if (h >= extern_table_size) h = 0;
- }
- /* Not seen yet. Record the object and output its contents. */
- extern_table[h].obj = v;
- extern_table[h].ofs = obj_counter;
- obj_counter++;
- switch(tag) {
- case String_tag: {
- mlsize_t len = string_length(v);
- if (len < 0x20) {
- putch(chan, PREFIX_SMALL_STRING + len);
- } else if (len < 0x100) {
- output_number(chan, CODE_STRING8, len, 8);
- } else {
- output_number(chan, CODE_STRING32, len, 32);
- }
- putblock(chan, String_val(v), len);
- size_32 += 1 + (len + 4) / 4;
- size_64 += 1 + (len + 8) / 8;
- break;
- }
- case Double_tag: {
- double buffer;
- if (sizeof(double) != 8)
- invalid_argument("output_compact_value: non-standard floats");
- putch(chan, CODE_DOUBLE);
- buffer = Double_val(v);
- #ifndef MOSML_BIG_ENDIAN
- Reverse_double(&buffer);
- #endif
- putblock(chan, (char *) &buffer, 8);
- size_32 += 1 + sizeof(double) / 4;
- size_64 += 1 + sizeof(double) / 8;
- break;
- }
- case Abstract_tag:
- case Final_tag:
- invalid_argument("output_compact_value: abstract value");
- break;
- case Closure_tag:
- invalid_argument("output_compact_value: functional value");
- break;
- default: {
- mlsize_t i;
- if (tag < 16 && sz < 8) {
- putch(chan, PREFIX_SMALL_BLOCK + tag + (sz << 4));
- } else {
- output_number(chan, CODE_BLOCK32, hd, 32);
- }
- size_32 += 1 + sz;
- size_64 += 1 + sz;
- for (i = 0; i < sz - 1; i++) emit_compact(chan, Field(v, i));
- v = Field(v, i);
- goto tailcall;
- }
- }
- }
- }
- }
-
- value extern_compact_val(chan, v) /* ML */
- struct channel * chan;
- value v;
- {
- value start_loc, final_loc;
- putword(chan, Compact_magic_number);
- start_loc = pos_out(chan);
- putword(chan, 0);
- putword(chan, 0);
- putword(chan, 0);
- extern_table_size = INITIAL_EXTERN_TABLE_SIZE;
- alloc_extern_table();
- obj_counter = 0;
- size_32 = 0;
- size_64 = 0;
- emit_compact(chan, v);
- #ifdef SIXTYFOUR
- if (size_32 >= (1L << 32) || size_64 >= (1L << 32)) {
- /* The object is so big its size cannot be written in the header.
- Besides, some of the block sizes or string lengths or shared offsets
- it contains may have overflowed the 32 bits used to write them. */
- failwith("output_compact_value: object too big");
- }
- #endif
- final_loc = pos_out(chan);
- seek_out(chan, start_loc);
- putword(chan, obj_counter);
- putword(chan, size_32);
- putword(chan, size_64);
- seek_out(chan, final_loc);
- stat_free((char *) extern_table);
- return Val_unit;
- }
-